/*
 * Copyright(C) 2009, kesalin All rights reserved.
 * 
 * File name : DropTarget.h
 * Brief     : Implement of IDropTarget.
 * Version   : 1.0
 * Author    : kesalin@gmail.com
 * Date      : 2009-6-5
 */

#pragma once

namespace DragDrop {

// IDropTargetImpl
template<class T>
class IDropTargetImpl : public IDropTarget {

	ATL::CComPtr<IDataObject> m_DataObject;

public:

	enum {
		DT_Enter,
		DT_Over,
		DT_Leave,
		DT_Drop
	};

public:

	STDMETHOD(DragEnter)(
		IDataObject* pDataObj,
		DWORD        grfKeyState,
		POINTL       pt,
		DWORD*       pdwEffect)
	{
		if (pDataObj == 0 || pdwEffect == 0) {
			return E_INVALIDARG;
		}

		m_DataObject = pDataObj;

		T* pThis = static_cast<T*>(this);
		HRESULT hRslt = pThis->OnDropEvent(
			DT_Enter,
			m_DataObject,
			grfKeyState,
			&pt,
			pdwEffect);
		if (FAILED(hRslt)) {
			return hRslt;
		}

		return S_OK;
	}

	STDMETHOD(DragOver)(
		DWORD  grfKeyState,
		POINTL pt,
		DWORD* pdwEffect)
	{
		if (pdwEffect == 0) {
			return E_INVALIDARG;
		}

		T* pThis = static_cast<T*>(this);
		HRESULT hRslt = pThis->OnDropEvent(
			DT_Over,
			m_DataObject,
			grfKeyState,
			&pt,
			pdwEffect);
		if (FAILED(hRslt)) {
			return hRslt;
		}

		return S_OK;
	}

	STDMETHOD(DragLeave)(void)
	{
		m_DataObject.Release();

		T* pThis = static_cast<T*>(this);
		HRESULT hRslt = pThis->OnDropEvent(
			DT_Leave,
			0,
			0,
			0,
			0);
		if (FAILED(hRslt)) {
			return hRslt;
		}

		return S_OK;
	}

	STDMETHOD(Drop)(
		IDataObject* pDataObj,
		DWORD        grfKeyState,
		POINTL       pt,
		DWORD*       pdwEffect)
	{
		m_DataObject.Release();

		if (pDataObj == 0 || pdwEffect == 0) {
			return E_INVALIDARG;
		}

		T* pThis = static_cast<T*>(this);
		HRESULT hRslt = pThis->OnDropEvent(
			DT_Drop,
			pDataObj,
			grfKeyState,
			&pt,
			pdwEffect);
		if (FAILED(hRslt)) {
			return hRslt;
		}

		return S_OK;
	}

}; // IDropTargetImpl

} // namespace DragDrop

